package service

import (
	"context"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"pay/api/bilinadmin"
	"pay/api/pay"
	"pay/internal/constant"
	"pay/internal/model"
	"pay/pkg/ecode"
	"pay/pkg/util"
)

// 收款账户下拉框
func (s *Service) PayAccountSelection(ctx context.Context, req *pay.PayAccountSelectionRequest) (
	resp *pay.PayAccountSelectionResp, err error) {
	resp = &pay.PayAccountSelectionResp{Accounts: make([]*pay.PayAccountSelectionView, 0)}
	switch req.PayType {
	case pay.PayType_PAY_ALIPAY:
		var configs []*model.AlipayConfigQueryModel
		if configs, resp.Total, err = s.dao.FindAlipayValidConfigsByPage(
			ctx, req.Token.SgId, req.PStoreId, req.PageNo, req.PageSize); err != nil {
			return
		}
		for _, config := range configs {
			resp.Accounts = append(resp.Accounts, &pay.PayAccountSelectionView{
				Id:    config.ID,
				Name:  config.Name,
				AppId: config.AppId,
			})
		}
	case pay.PayType_PAY_WECHAT:
		var configs []*model.WechatConfig
		if configs, resp.Total, err = s.dao.FindWechatValidConfigsByPage(
			ctx, req.Token.SgId, req.PStoreId, req.PageNo, req.PageSize); err != nil {
			return
		}
		for _, config := range configs {
			resp.Accounts = append(resp.Accounts, &pay.PayAccountSelectionView{
				Id:            config.ID,
				Name:          config.Name,
				MerchantId:    config.MerchantId,
				PrincipalName: config.PrincipalName,
			})
		}
	case pay.PayType_PAY_BYTEDANCE:
		var configs []*model.ByteDanceConfig
		if configs, resp.Total, err = s.dao.FindByteDanceConfigsByPage(
			ctx, req.Token.SgId, req.PStoreId, req.PageNo, req.PageSize); err != nil {
			return
		}
		for _, config := range configs {
			resp.Accounts = append(resp.Accounts, &pay.PayAccountSelectionView{
				Id:    config.ID,
				Name:  config.Name,
				AppId: config.AppId,
			})
		}
	default:
		err = ecode.BadRequest("不支持所选收款账户类型")
		return
	}
	return
}

// 查看全局收款设置
func (s *Service) GetPayGlobalConfig(ctx context.Context, req *pay.CommonRequest) (
	resp *pay.GetPayGlobalConfigResp, err error) {
	if err = s.downstream.CheckAdmin(ctx, req.Token, 0); err != nil {
		return
	}
	var config *model.GlobalConfig
	if config, err = s.dao.GetGlobalConfig(ctx, req.Token.SgId); err != nil {
		if errors.Cause(err) == gorm.ErrRecordNotFound {
			err = nil
			resp = &pay.GetPayGlobalConfigResp{
				Config: pay.AccountConfig_ACCOUNT_CONFIG_BY_BRAND,
				Stores: make([]*pay.AccountConfigStoreView, 0),
			}
		}
		return
	}
	resp = &pay.GetPayGlobalConfigResp{Config: pay.AccountConfig(config.ConfigType)}
	if len(config.StoreIds) != 0 {
		if resp.Stores, err = s.downstream.GetStoreListByStoreIds(ctx, config.StoreIds); err != nil {
			return
		}
	} else {
		resp.Stores = make([]*pay.AccountConfigStoreView, 0)
	}
	return
}

// 修改全局收款设置
func (s *Service) EditPayGlobalConfig(ctx context.Context, req *pay.EditPayGlobalConfigRequest) (
	resp *pay.DefaultResp, err error) {
	if err = s.downstream.CheckAdmin(ctx, req.Token, 0); err != nil {
		return
	}
	var stores []*pay.AccountConfigStoreView
	storeIds := util.FormatInt32ArrayToIntArray(req.StoreIds)
	if stores, err = s.downstream.GetStoreListByStoreIds(ctx, storeIds); err != nil {
		return
	}
	if len(stores) != len(storeIds) {
		err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选门店包含已删除门店，请刷新列表重试")
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var config *model.GlobalConfig
		if config, err = s.dao.GetGlobalConfig(ctx, req.Token.SgId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				// 首次配置
				if err = s.dao.Create(ctx, &model.GlobalConfig{
					SgId:       req.Token.SgId,
					ConfigType: uint8(req.Config),
					StoreIds:   storeIds,
					Operator:   req.Token.EmpId,
				}); err != nil {
					return
				}
			}
			return
		} else {
			config.ConfigType = uint8(req.Config)
			config.StoreIds = storeIds
			config.Operator = req.Token.EmpId
			if err = s.dao.Save(ctx, config); err != nil {
				return
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &pay.DefaultResp{Status: true}
	return
}

// 查看店铺收款设置列表
func (s *Service) GetPayStoreConfig(ctx context.Context, req *pay.GetPayStoreConfigRequest) (
	resp *pay.GetPayStoreConfigResp, err error) {
	if err = s.downstream.CheckAdmin(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var (
		storeIds     []uint32
		storeConfigs []*model.StoreConfig
	)
	if req.PStoreId == 0 {
		var (
			brandName string
			reply     *bilinadmin.StoresInfoReply
		)
		if brandName, err = s.downstream.GetBrandName(ctx, req.Token.SgId); err != nil {
			return
		}
		if reply, err = s.downstream.GetStoreListByPage(ctx, req.Token.SgId, req.PageNo, req.PageSize); err != nil {
			return
		}
		resp = &pay.GetPayStoreConfigResp{
			Total:  int64(reply.Total),
			Stores: make([]*pay.PayStoreConfigView, len(reply.Stores)+1),
		}
		storeIds = make([]uint32, len(reply.Stores)+1)
		storeIds[0] = 0
		resp.Stores[0] = &pay.PayStoreConfigView{
			StoreId:      0,
			StoreName:    brandName,
			IsCustomized: false,
			Account:      nil,
		}
		for i, store := range reply.Stores {
			storeIds[i+1] = uint32(store.StoreId)
			resp.Stores[i+1] = &pay.PayStoreConfigView{
				StoreId:      uint32(store.StoreId),
				StoreName:    store.StoreName,
				IsCustomized: false,
				Account:      nil,
			}
		}
	} else {
		var stores []*pay.AccountConfigStoreView
		if stores, err = s.downstream.GetStoreListByStoreIds(ctx, []int{int(req.PStoreId)}); err != nil {
			return
		}
		if len(stores) != 1 {
			err = constant.ErrObjectNotExist
			return
		}
		storeIds = []uint32{req.PStoreId}
		resp = &pay.GetPayStoreConfigResp{
			Total: 1,
			Stores: []*pay.PayStoreConfigView{{
				StoreId:      req.PStoreId,
				StoreName:    stores[0].Name,
				IsCustomized: false,
				Account:      nil,
			}},
		}
	}
	storeConfigMap := make(map[uint32]*model.StoreConfig)
	accountMap := make(map[uint32]*pay.PayAccountSelectionView)
	if len(storeIds) != 0 {
		if storeConfigs, err = s.dao.FindStoreConfigsByStoreIds(
			ctx, req.Token.SgId, storeIds, req.PayType, pay.BizType_BIZ_MALL); err != nil {
			return
		}
		accountIDMap := make(util.Int32BoolMap)
		for _, storeConfig := range storeConfigs {
			storeConfigMap[storeConfig.PStoreId] = storeConfig
			accountIDMap[storeConfig.AccountId] = true
		}
		if len(accountIDMap) != 0 {
			switch req.PayType {
			case pay.PayType_PAY_WECHAT:
				var configs []*model.WechatConfig
				if configs, err = s.dao.FindWechatConfigsByIds(
					ctx, accountIDMap.GetKeys(), req.Token.SgId); err != nil {
					return
				}
				for _, config := range configs {
					accountMap[config.ID] = &pay.PayAccountSelectionView{
						Id:            config.ID,
						Name:          config.Name,
						MerchantId:    config.MerchantId,
						PrincipalName: config.PrincipalName,
					}
				}
			case pay.PayType_PAY_ALIPAY:
				var configs []*model.AlipayConfigQueryModel
				if configs, err = s.dao.FindAlipayConfigsByIds(
					ctx, accountIDMap.GetKeys(), req.Token.SgId); err != nil {
					return
				}
				for _, config := range configs {
					accountMap[config.ID] = &pay.PayAccountSelectionView{
						Id:    config.ID,
						Name:  config.Name,
						AppId: config.AppId,
					}
				}
			case pay.PayType_PAY_BYTEDANCE:
				var configs []*model.ByteDanceConfig
				if configs, err = s.dao.FindByteDanceConfigsByIds(
					ctx, accountIDMap.GetKeys(), req.Token.SgId); err != nil {
					return
				}
				for _, config := range configs {
					accountMap[config.ID] = &pay.PayAccountSelectionView{
						Id:    config.ID,
						Name:  config.Name,
						AppId: config.AppId,
					}
				}
			default:
				err = ecode.BadRequest("不支持所选收款账户类型")
				return
			}
		}
	}
	for _, storeReply := range resp.Stores {
		if storeConfig, ok := storeConfigMap[storeReply.StoreId]; ok {
			storeReply.IsCustomized = storeConfig.IsCustomized
			storeReply.Account = accountMap[storeConfig.AccountId]
		}
	}
	return
}

// 绑定收款账户到品牌&店铺
func (s *Service) BindPayStoreConfig(ctx context.Context, req *pay.BindPayStoreConfigRequest) (
	resp *pay.DefaultResp, err error) {
	if err = s.downstream.CheckAdmin(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if req.PStoreId != 0 && req.PStoreId != req.StoreId {
		err = constant.ErrPermissionError
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		switch req.PayType {
		case pay.PayType_PAY_ALIPAY:
			if _, err = s.dao.GetAlipayConfig(ctx, req.AccountId, req.Token.SgId, req.PStoreId); err != nil {
				if errors.Cause(err) == gorm.ErrRecordNotFound {
					err = constant.ErrObjectNotExist
					return
				}
				return
			}
		case pay.PayType_PAY_WECHAT:
			if _, err = s.dao.GetWechatConfig(ctx, req.AccountId, req.Token.SgId, req.PStoreId); err != nil {
				if errors.Cause(err) == gorm.ErrRecordNotFound {
					err = constant.ErrObjectNotExist
					return
				}
				return
			}
		case pay.PayType_PAY_BYTEDANCE:
			if _, err = s.dao.GetByteDanceConfig(ctx, req.AccountId, req.Token.SgId, req.PStoreId); err != nil {
				if errors.Cause(err) == gorm.ErrRecordNotFound {
					err = constant.ErrObjectNotExist
					return
				}
				return
			}
		}
		var storeConfig *model.StoreConfig
		if storeConfig, err = s.dao.GetStoreConfigByStoreIdWithStatus(
			ctx, req.Token.SgId, req.StoreId, req.PayType, pay.BizType_BIZ_MALL); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				// 新增配置
				if err = s.dao.Create(ctx, &model.StoreConfig{
					SgId:         req.Token.SgId,
					PStoreId:     req.PStoreId,
					BizType:      uint8(pay.BizType_BIZ_MALL),
					PayType:      uint8(req.PayType),
					AccountId:    req.AccountId,
					IsCustomized: req.PStoreId == req.StoreId,
					Status:       true,
					Operator:     req.Token.EmpId,
				}); err != nil {
					return
				}
			}
			return
		} else if !storeConfig.Status {
			// 更新配置
			storeConfig.AccountId = req.AccountId
			storeConfig.IsCustomized = req.PStoreId == req.StoreId
			storeConfig.Status = true
			storeConfig.Operator = req.Token.EmpId
			if err = s.dao.AutoUpdate(ctx, storeConfig); err != nil {
				return
			}
		} else {
			err = ecode.AppendMessage(constant.ErrNeedRefresh, "门店已经绑定支付方式，请刷新列表")
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &pay.DefaultResp{Status: true}
	return
}

// 解绑收款账户到品牌&店铺
func (s *Service) UnbindPayStoreConfig(ctx context.Context, req *pay.UnbindPayStoreConfigRequest) (
	resp *pay.DefaultResp, err error) {
	if err = s.downstream.CheckAdmin(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if req.PStoreId != 0 && req.PStoreId != req.StoreId {
		err = constant.ErrPermissionError
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var storeConfig *model.StoreConfig
		if storeConfig, err = s.dao.GetStoreConfigByStoreIdWithStatus(
			ctx, req.Token.SgId, req.StoreId, req.PayType, pay.BizType_BIZ_MALL); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		} else if storeConfig.Status {
			if !storeConfig.IsCustomized && req.PStoreId != 0 {
				err = ecode.AppendMessage(constant.ErrForbiddenAction, "当前收款账户由总部配置，仅允许从总部发起解绑")
				return
			}
			// 更新配置
			storeConfig.AccountId = 0
			storeConfig.IsCustomized = false
			storeConfig.Status = false
			storeConfig.Operator = req.Token.EmpId
			if err = s.dao.AutoUpdate(ctx, storeConfig); err != nil {
				return
			}
		} else {
			err = ecode.AppendMessage(constant.ErrNeedRefresh, "门店已经解绑支付方式，请刷新列表")
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &pay.DefaultResp{Status: true}
	return
}
